﻿using FFmpeg.AutoGen;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace FFmpegWinui3.UlitFolder
{

    /// <summary>
    /// 视频帧转换
    /// </summary>
    public unsafe class VideoFrameConverter : IDisposable
    {
        /// <summary>
        /// 转换帧缓冲句柄
        /// </summary>
        private readonly IntPtr _convertedFrameBufferPtr;
        /// <summary>
        /// 目标帧大小
        /// </summary>
        private readonly Size _destinationSize;
        /// <summary>
        /// 目标数据
        /// </summary>
        private readonly byte_ptrArray4 _dstData;
        /// <summary>
        /// 目标字节偏移量的整数
        /// </summary>
        private readonly int_array4 _dstLinesize;
        private readonly SwsContext* _pConvertContext;

        /// <summary>
        /// 视频帧转换
        /// </summary>
        /// <param name="sourceSize">源大小</param>
        /// <param name="sourcePixelFormat">源格式</param>
        /// <param name="destinationSize">目标大小</param>
        /// <param name="destinationPixelFormat">目标格式</param>
        /// <exception cref="ApplicationException">应用程序异常</exception>
        public VideoFrameConverter(Size sourceSize, AVPixelFormat sourcePixelFormat,
            Size destinationSize, AVPixelFormat destinationPixelFormat)
        {
            //目标大小
            _destinationSize = destinationSize;
            //上下文
            _pConvertContext = ffmpeg.sws_getContext(sourceSize.Width,
                sourceSize.Height,
                sourcePixelFormat,
                destinationSize.Width,
                destinationSize.Height,
                destinationPixelFormat,
                ffmpeg.SWS_FAST_BILINEAR,
                null,
                null,
                null);

            if (_pConvertContext == null)
                new ApplicationException("初始化视频帧转换失败.");
            //转换帧缓冲区大小
            var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat,
                destinationSize.Width,
                destinationSize.Height,
                1);
            //转换帧缓冲区句柄
            _convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);
            _dstData = new byte_ptrArray4();
            _dstLinesize = new int_array4();

            ffmpeg.av_image_fill_arrays(ref _dstData,
                ref _dstLinesize,
                (byte*)_convertedFrameBufferPtr,
                destinationPixelFormat,
                destinationSize.Width,
                destinationSize.Height,
                1);
        }

        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {
            Marshal.FreeHGlobal(_convertedFrameBufferPtr);
            ffmpeg.sws_freeContext(_pConvertContext);
        }

        /// <summary>
        /// 帧转换
        /// </summary>
        /// <param name="sourceFrame"></param>
        /// <returns></returns>
        public AVFrame Convert(AVFrame sourceFrame)
        {

            ffmpeg.sws_scale(_pConvertContext,
                sourceFrame.data,
                sourceFrame.linesize,
                0,
                sourceFrame.height,
                _dstData,
                _dstLinesize);

            var data = new byte_ptrArray8();
            data.UpdateFrom(_dstData);
            var linesize = new int_array8();
            linesize.UpdateFrom(_dstLinesize);

            return new AVFrame
            {
                data = data,
                linesize = linesize,
                width = _destinationSize.Width,
                height = _destinationSize.Height
            };
        }
    }


}
